/**
 * 
 */
package edu.umd.clip.lm.util;

import java.io.Serializable;
import java.util.*;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class CompactReadOnlyLong2ObjectHashMap<V> implements Serializable {
	private static final long serialVersionUID = 1L;

	private final CompactReadOnlyLongHashSet keys;
	private final V values[];
	
	public CompactReadOnlyLong2ObjectHashMap(Map<Long, V> map) {
		this(map, CompactReadOnlyLongHashSet.DEFAULT_LOAD_FACTOR);
	}
	public CompactReadOnlyLong2ObjectHashMap(Map<Long, V> map, float loadFactor) {
		long keys[] = new long[map.size()];
		int pos = 0;
		for(long key : map.keySet()) {
			keys[pos++] = key;
		}
		this.keys = new CompactReadOnlyLongHashSet(keys, loadFactor);
		this.values = (V []) new Object[keys.length];

		for(Map.Entry<Long, V> e : map.entrySet()) {
			pos = this.keys.getKeyPosition(e.getKey());
			this.values[pos] = e.getValue();
		}
	}
	
	public CompactReadOnlyLong2ObjectHashMap(long[] keys, V[] values) {
		this(keys, values, CompactReadOnlyLongHashSet.DEFAULT_LOAD_FACTOR);
	}
	public CompactReadOnlyLong2ObjectHashMap(long[] keys, V[] values, float loadFactor) {
		assert(keys.length == values.length);
		
		this.keys = new CompactReadOnlyLongHashSet(keys, loadFactor);
		this.values = (V[]) new Object[values.length];
		for(int i=0; i<keys.length; ++i) {
			int pos = this.keys.getKeyPosition(keys[i]);
			this.values[pos] = values[i]; 
		}
	}
	
	public final V get(long key) {
		int pos = keys.getKeyPosition(key);
		if (pos >= 0) return values[pos];
		return null;
	}

	public boolean containsKey(long key) {
		return keys.containsKey(key);
	}

	public final int size() {
		return keys.size();
	}
	
	public HashMap<Long, V> toHashMap() {
		HashMap<Long, V> map = new HashMap<Long, V>(size());
		long keys[] = this.keys.toArray();
		for(long key : keys) {
			V value = get(key);
			map.put(key, value);
		}
		return map;
	}
	
	public long[] keys() {
		return keys.toArray();
	}

	public Object[] values() {
		return values;
	}
	
	@SuppressWarnings("unchecked")
	public V[] values(V[] copy) {
		if (copy.length >= values.length) {
			System.arraycopy(values, 0, copy, 0, values.length);
			if (values.length < copy.length) {
				copy[values.length] = null;
			}
			return copy;
		} else {
			return (V[]) Arrays.copyOf(values, values.length, copy.getClass());
		}
	}
	
	public class Iterator {
		private int pos;
		
		private Iterator() {
			pos = -1;
		}
		
		public boolean hasNext() {
			return pos+1 < size(); 
		}
		
		public void next() {
			++pos;
		}
		
		public long key() {
			return keys()[pos];
		}
		
		public V value() {
			return values[pos];
		}
	}
}
